﻿#include <algorithm>
#include "ServiceMgr.h"
#include "base/core/os/debug.h"
#include "base/core/os/time.h"
#include "base/core/os/string.h"
#include "base/core/com_define.h"
#include "base/core/lua_parser.h"
#include "base/core/utility.h"
#include "base/core/buffer_pool.h"
#include "base/core/compress.h"
#include "base/core/Profiler.h"
#include "Common/NetPack/NetPack.h"
#include "Common/Utility/ServerTime.h"
#include "Common/Event/Event.h"
#include "Common/Timer/ITimer.h"
#include "Common/Timer/TimerAxis.h"
#include "ProtoBuffer/AllProtocol.h"
#include "Common/TaskBalance/TaskBalance.h"
#include "Server/DBProxyServiceFactory.h"
#include "Server/CenterServiceFactory.h"
#include "Server/LogicServiceFactory.h"
#include "Server/LoginServiceFactory.h"
#include "Server/LogServiceFactory.h"
#include "Common/TableData/TableMgr.h"
#include "Common/TableDataEx/TableExMgr.h"
#include "Server/MasterServiceFactory.h"
#include "Server/GateServiceFactory.h"
#include "Server/ZoneServiceFactory.h"
#include "base/core/utility.h"
#include "Common/ErrCollect/ErrCollect.h"
#include "Common/Item/ItemMgr.h"
#include "Common/AttrMgr/AttrMgr.h"
#include "Common/ReliveMgr/ReliveMgr.h"
#include "Common/ProfileLog/ProfileLog.h"
#include "../GateServer/GateService.h"

#ifndef WIN32
#include <sys/resource.h>
#endif

using namespace std;
using namespace ProtoBuf;

namespace
{
    static const uint32_t s_cmd_count  = 64;
    static const uint32_t s_frame      = 30;
    static const uint32_t s_frame_time = 1000 / s_frame;
    static const char     s_config_file[] = "./config.lua";

	static const int  s_maxLintCount = 6000;
	static const char s_logDirector[] = "log";
	static const char s_logFileIdenty[] = "mmo";

    static const uint32_t s_decompressLength = MAX_CLIENT_NET_PACK_LENGTH + sizeof(NetPack);
    static PROFILE_TIMER  s_Timer_ServiceUpdate[SERVICE_COUNT];
   // static PROFILE_TIMER  s_Timer_ClientProtocol[NET_PROTOCOL_SERVER_TO_CLIENT_COUNT];
   // static PROFILE_TIMER  s_Timer_ServiceProtocol[NET_PROTOCOL_SERVER_COUNT];
    
	class TimerInit
	{
    public:
        TimerInit() 
		{
            char timerName[PROFILER_MAX_TIMER_NAME_LEN];

            for (unsigned i = 0; i < countof(s_Timer_ServiceUpdate); ++i) 
			{
                snprintf(timerName, countof(timerName), "%s update", s_service_name[i].c_str());
                timerName[countof(timerName) - 1] = '\0';

                s_Timer_ServiceUpdate[i].SetName(timerName);
            }
        }
    };
    static TimerInit g_TimerInit;
}

ConsoleCmd::ConsoleCmd(const char* c/* = NULL*/) 
{
    memset(cmd, 0, sizeof(cmd));
    if (c) 
	{
		SafeCopyString(cmd, countof(c), c);
    }
}

ConsoleCmd& ConsoleCmd::operator = (const ConsoleCmd& c) 
{
    SafeCopyString(cmd, countof(c.cmd), c.cmd);
    return (*this);
}

NetCallbackImp::NetCallbackImp() 
{
    m_uncompressBuf = new char[s_decompressLength];
}

NetCallbackImp::~NetCallbackImp() 
{
    if (m_uncompressBuf != NULL) 
	{
        delete[] m_uncompressBuf;
        m_uncompressBuf = NULL;
    }
}

bool NetCallbackImp::OnRecv(const char* data, int len, ISession* session, uint64_t time_ms)
{
    bool result = false;
    uint32_t retCode = 0;
    const NetPack* pack = NULL;
   // NetPackHandle* handle = NULL;
	IMessageDispatch *messageDispatch = nullptr;
	uint16_t nModuleId = 0;
	uint16_t nActionId = 0;
    RECV_PACKAGE package;
    Service* service = nullptr;
	uint64_t handleTime = 0;

    MMOLOG_ASSERT_EXIT(data);
    MMOLOG_ASSERT_EXIT(session);

    MMOLOG_PROCESS_ERROR(len >= (int)sizeof(NetPack));
    pack = reinterpret_cast<const NetPack*>(data);	
	messageDispatch = reinterpret_cast<IMessageDispatch*>(session->GetNetPackHandle());
	MMOLOG_PROCESS_ERROR(messageDispatch);
	service = (Service*)messageDispatch->GetService();
	MMOLOG_PROCESS_ERROR(service);

	nActionId = pack->GetCmd();
	nModuleId = pack->GetModule();
	
    package.session = session;
	package.moduleId = nModuleId;
	package.cmd = nActionId;
	package.time_ms = time_ms;

    if (!pack->IsCompressed())
	{
        package.msg = data;
        package.len = len;
        package.dataAfterHead = data + sizeof(NetPack);
        package.sizeAfterHead = len - sizeof(NetPack);
    } 
	else 
	{
        retCode = Decompress((data + sizeof(NetPack)),
							(len - sizeof(NetPack)),
							(m_uncompressBuf + sizeof(NetPack)),
							(s_decompressLength - sizeof(NetPack)));
        MMOLOG_PROCESS_ERROR(retCode > 0);
        *((NetPack*)m_uncompressBuf) = *pack;
        package.msg = m_uncompressBuf;
        package.len = retCode + sizeof(NetPack);
        package.dataAfterHead = m_uncompressBuf + sizeof(NetPack);
        package.sizeAfterHead = retCode;
    }

	if (service->GetType() != GATE_SERVER)
	{
#ifdef WIN32
		QueryPerformanceCounter((LARGE_INTEGER*)&package.handleTime_Nsec);
#else
		clock_gettime(CLOCK_MONOTONIC, &package.handleTime_Nsec);
#endif // WIN32
	}

	switch (session->GetMark())
	{
	case CLIENT_MART:
		retCode = service->TrueClientMessage(package);
		MMOLOG_PROCESS_ERROR(retCode);
		break;
	case GATE_SERVER:
		messageDispatch->dispatchGateMessage(nModuleId, nActionId, package);
		handleTime = service->GetNaSecDiffTime(package);
		break;
	case DBPROXY_SERVER:
		messageDispatch->dispatchDBProxyMessage(nModuleId, nActionId, package);
		handleTime = service->GetNaSecDiffTime(package);
		break;
	default:
		messageDispatch->dispatchServerMessage(nModuleId, nActionId, package);
		handleTime = service->GetNaSecDiffTime(package);
		break;
	}
	g_GetProfileLogMgr()->RecvCmdRecord(service->GetType(), session->GetMark(), package.cmd, package.len, handleTime);
	result = true;
	
//	if (DBPROXY_SERVER == service->GetType())
//	{
//		messageDispatch->dispatchServerMessage(nModuleId, nActionId, package);
//	}
//	else
//	{
//		if (CLIENT_MART == session->GetMark())  //�յ��ͻ��˵���Ϣ����(����ֻ�е�½����������)
//		{
//			retCode = service->TrueClientMessage(package);
//			MMOLOG_PROCESS_ERROR(retCode);

//			endTime = Time::Now().UnixNano();
//			result = true;
//			goto Exit0;
//		}
//		else if (GATE_SERVER == session->GetMark() ) //���ط�������Ϣ����
//		{
//			messageDispatch->dispatchGateMessage(nModuleId, nActionId, package);
//		}
//		else if (DBPROXY_SERVER == session->GetMark()) //�յ�DB��Ϣ
//		{
//			messageDispatch->dispatchDBProxyMessage(nModuleId, nActionId, package);
//		}
//		else
//		{
//			//��������������Ϣ
//			messageDispatch->dispatchServerMessage(nModuleId, nActionId, package);
//		}
//	}
//	endTime = Time::Now().UnixNano();
//	result = true;

//Exit1:
//    result = true;
Exit0:
    return result;
}

bool NetCallbackImp::OnConnect(ISession* session, void* req, void* context, bool success) 
{
    BEGIN_PROFILE("NetCallbackImp::OnConnect");

    MMO_ASSERT(req);
    OnConnectFunc func = reinterpret_cast<OnConnectFunc>(req);
    MMO_ASSERT(func);
    
    if (func) 
	{
        func(session, context, success);
    }
    
    END_PROFILE();
    return true;
}

bool NetCallbackImp::OnClose(ISession* session, CloseFlag flag) 
{
    BEGIN_PROFILE("NetCallbackImp::OnClose");

    MMO_ASSERT(session);
    void* req = nullptr;
    void* context = nullptr;

    session->GetUserReq(&req, &context);
    if (req) 
	{
        OnCloseFunc func = reinterpret_cast<OnCloseFunc>(req);
        if (func) 
		{
            func(session, context, flag);
        }
    }

    END_PROFILE();
    return true;
}

bool NetCallbackImp::OnAccept(ISession* session, void* req, void* context) 
{
    BEGIN_PROFILE("NetCallbackImp::OnAccept");

    MMO_ASSERT(session && req);

    OnAcceptFunc func = reinterpret_cast<OnAcceptFunc>(req);
    MMO_ASSERT(func);
    if (func) 
	{
        func(session, context);
    }
    
    END_PROFILE();
    return true;
}

//------------------------------------------------------------------------------------------------
ServiceMgr::ServiceMgr()
	: m_serviceCount(0),
	m_loopSleep(0),
	m_netInit(),
	m_net(NULL) 
{
    memset(m_services, 0, sizeof(m_services));
    memset(m_serviceMaker, 0, sizeof(m_serviceMaker));
    m_ExitFlag = false;
}

ServiceMgr::~ServiceMgr() 
{}

bool ServiceMgr::Init(const char* configFile)
{
    bool result  = false;
    bool retCode = false;
    BufferPool* globalPool = NULL;
	LogConfig   logConf;

#ifndef WIN32
    rlimit sLimit;
    sLimit.rlim_cur = -1;
    sLimit.rlim_max = -1;
    ::setrlimit(RLIMIT_CORE, &sLimit);
#endif
    if (!_LoadConfig(configFile, logConf)) 
	{
        LogErrFmtPrint("[server] load config %s fail", configFile);
        goto Exit0;
    }

	retCode = _LogInit(logConf);
	MMOLOG_PROCESS_ERROR(retCode);
	retCode = LogAlwaysFmtPrint("mmo server start..., Server.cpp build time %s %s", __TIME__, __DATE__);
	MMOLOG_PROCESS_ERROR(retCode);

    retCode = _RegisteServiceMaker();
    MMOLOG_PROCESS_ERROR(retCode);

    globalPool = MakeGlobalBufferPool();
    if (globalPool == NULL) 
	{
        LogErrPrint("[server] make global buffer pool is null");
        goto Exit0;
    }

    if (!g_MakeGlobalServerTime()->Init(s_frame)) 
	{
        LogErrPrint("[server] global process handle input thread fail");
        goto Exit0;
    }

    m_net = CreateNet();
    if (m_net == NULL) 
	{
        LogErrPrint("[server] create net is null");
        goto Exit0;
    }

    if (!m_net->Init(m_netInit)) 
	{
        LogErrPrint("[server] init net fail");
        goto Exit0;
    }

	if (!g_MakeEvent()->Init())
	{
		LogErrPrint("[server] init event fail");
		goto Exit0;
	}

	if (!g_MakeTimerAxis()->Init())
	{
		LogErrPrint("[server] init timer fail");
		goto Exit0;
	}

	if (!g_MakeTaskBalanceMgr()->Init())
	{
		LogErrPrint("[server] init task balance fail");
		goto Exit0;
	}

    if (!_LoadService(configFile)) 
	{
        LogErrPrint("[server] load service fail");
        goto Exit0;
    }

    retCode = m_inputThread.RunThread(_InputThreadFunction, this);
    if (!retCode) 
	{
        LogErrPrint("[server] run input thread fail");
        goto Exit0;
    }

    result = true;
Exit0:
    return result;
}

bool ServiceMgr::UnInit() 
{
    bool result  = false;
    bool retCode = false;
	bool usetable = false;

    m_inputThread.StopThread(Thread::FORCE_CANCEL); // maybe block by fgets(). not wait it

	for (unsigned i = 0; i < countof(m_services); ++i)
	{
		if (m_services[i])
		{
			retCode = _DelService(m_services[i]);
			MMOLOG_PROCESS_ERROR(retCode);
			m_services[i] = NULL;
			if (i == LOGIC_SERVER || i == CENTER_SERVER)
			{
				usetable = true;
			}
		}
	}
	m_serviceCount = 0;

	LogInfoPrint("[server] uninit network ...");
	if (m_net != NULL)
	{
		m_net->UnInit();
		DeleteNet(m_net);
		m_net = NULL;
	}

	g_GetEvent()->UnInit();
	g_DelEvent();

	g_GetTimerAxis()->UnInit();
	g_DelTimerAxis();

    g_GetGlobalServerTime()->UnInit();
    g_DelGlobalServerTime();

	if (usetable)
	{
		g_GetTableExMgr()->UnInit();
		g_DelTableExMgr();

		g_GetTableDataMgr()->UnInit();
		g_DelTableDataMgr();

		g_GetItemMgr()->UnInit();
		g_DelItemMgr();

		g_GetAttrMgr()->UnInit();
		g_DelAttrMgr();

		g_GetReliveMgr()->UnInit();
		g_DelReliveMgr();
	}

	g_GetTaskBalanceMgr()->UnInit();
	g_DelTaskBalanceMgr();

	g_GetProfileLogMgr()->UnInit();
	g_DelProfileLogMgr();

	//错误日志收集服之前把回调指针设置null,以免退出的时候崩溃
	retCode = SetLogCallBack(NULL);
	MMOLOG_PROCESS_ERROR(retCode);

	g_DelErrCollectMgr();
    retCode = DeleteGlobalBufferPool();
    MMOLOG_PROCESS_ERROR(retCode);

    result = true;
Exit0:
    return result;
}

void ServiceMgr::_InputThreadFunction(void *param) 
{
    ConsoleCmd  command;
    ServiceMgr *_this = reinterpret_cast<ServiceMgr *>(param);
    MMO_ASSERT(_this);

    // main thread init will output many log, wait some time before show input message
    Time::Sleep(500); 
    printf("\nplease enter the command:\n");
    for (;;) 
	{
        memset(command.cmd, 0, sizeof(command.cmd));
        fgets(command.cmd, sizeof(command.cmd), stdin); // block function should run in work thread

        char *enter = strchr(command.cmd, '\n');
        if (enter)
            *enter = '\0';

        if (command.cmd[0] == '\0') {
            Time::Sleep(100);
            continue;
        }

        _this->m_consoleCmdLock.Lock();
        _this->m_consoleCmd.push(command);
        _this->m_consoleCmdLock.Unlock();

        if (stricmp(command.cmd, "q") == 0 ||
            stricmp(command.cmd, "quit") == 0) 
		{
            break;
        }

		if (command.cmd[0]!='\0')  //��ָ����
		{
			//��ָ��ո�ֿ�
			std::vector<std::string> vResult;
			std::string strCmd(command.cmd);
			std::string strSplit(" ");
			CommonApi::SplitStr(strCmd, strSplit,&vResult);
			if ((uint32_t)vResult.size()>=2)
			{
				_this->m_services[CENTER_SERVER]->OnGM(vResult);
			}
			LogDebugFmtPrint("cmd=%s", command.cmd);
		}

        Time::Sleep(100);
    }
}

bool ServiceMgr::Loop() 
{
    bool result  = false;
    bool retCode = false;
    uint64_t start = Time::Tick();
    uint64_t end = 0;
	uint64_t recordMsec = 0;
    uint32_t cost = 0;
	ServiceMgrProfile sprofile;

    int exitCount = 0;
    
    ResetAllProfileTimer();
    BEGIN_PROFILE("main loop");
    static PROFILE_TIMER s_NetLoop("net loop"); // use twice

    g_GetGlobalServerTime()->Update(start);   //


	try
	{
		BEGIN_PROFILE("TimerAxis::Update");
		g_GetTimerAxis()->Update();
		END_PROFILE();
		recordMsec = Time::Tick();
        sprofile.timerAxisMs = (float)(recordMsec > start ? (recordMsec - start) : 0);

		BEGIN_PROFILE("TimerAxis::UpdateFix");
		g_GetTimerAxis()->UpdateFix();
		END_PROFILE();
		end = Time::Tick();
        sprofile.timerFixMs = (float)(end > recordMsec ? (end - recordMsec) : 0);
		recordMsec = end;
	}
	catch (...)
	{
		LogErrFmtPrint("TimerAxis update error....");
	}
	
	BEGIN_PROFILE("TaskBalance::Update");
	g_GetTaskBalanceMgr()->Update(start);
	END_PROFILE();
	end = Time::Tick();
	sprofile.taskblanceMs = (float)(end > recordMsec ? (end - recordMsec) : 0);
	recordMsec = end;

    if (!m_ExitFlag) 
	{
        BEGIN_PROFILE("_HandleConsoleCmd");
        _HandleConsoleCmd();
        END_PROFILE();
    } 
	else 
	{
        BEGIN_PROFILE("_TriggerQuit");
        _TriggerQuit();
        END_PROFILE();
    }

    if (m_serviceCount > 0)  
	{
        BeginProfile(&s_NetLoop);
        m_net->Loop(false, true, 0);  //recv
        EndProfile();
		end = Time::Tick();
		sprofile.netRecvMs = (float)(end > recordMsec ? (end - recordMsec) : 0);
		recordMsec = end;
    }

    for (unsigned i = 0; i < countof(m_services); ++i) 
	{
        if (m_services[i]) 
		{
            BeginProfile(&s_Timer_ServiceUpdate[i]);
            retCode = m_services[i]->Loop(start);
            EndProfile();

			end = Time::Tick();
			sprofile.serverLoopMs[i] = (float)(end > recordMsec ? (end - recordMsec) : 0);
			recordMsec = end;
            if (!retCode) 
			{
                ++exitCount;
            }
        }
    }

    if (m_serviceCount > 0) 
	{
        BeginProfile(&s_NetLoop);
        m_net->Poll(true, false, 0);  // must only do send
        EndProfile();

		end = Time::Tick();
		sprofile.netSendMs = (float)(end > recordMsec ? (end - recordMsec) : 0);
		recordMsec = end;
    }

    end = Time::Tick();
    cost = (uint32_t)(end > start ? (end - start) : 0);
    m_loopSleep = s_frame_time > cost ? (s_frame_time - cost) : 0;

	sprofile.costTimeMs = (float)cost;

    if (m_serviceCount > 0 && exitCount == m_serviceCount) 
	{
        LogInfoPrint("[server] all service has quit finish");
        goto Exit0;
    }

	g_GetProfileLogMgr()->SeviceMgrProfileRecord(sprofile, end);

	if (m_loopSleep > 0)
	{
		BEGIN_PROFILE("sleep");
		Time::Sleep(m_loopSleep);
		END_PROFILE();
	}
	Time::Sleep(1);
    result = true;
Exit0:
    END_PROFILE();

	//if (cost > s_frame_time)
	//{
	//	LogDebugFmtPrint("[server] lost frame, total cost time=%d(as fail), start:%ld, end:%ld ", cost, start, end);
	//	OutputTopProfileTimer();
	//}

	//注册timer名称 
	//这里添加要测性能的模块，把入口的pritime函数名注册进来
	//std::unordered_map<std::string, double> profileKey;

	//例子:net loop 处理时间超过10毫秒就会打印，如果需要更详细的时间分布，则在net loop内部再打点，会自动打印时间消耗百分比
	//profileKey["skill use"] = 0.1f; 

	//去掉注释就可以打印了
	//OutputProfileTimerByNames(profileKey);

    return result;
}

bool ServiceMgr::SetExitSignal() 
{
    m_ExitFlag = true;
    return true;
}

bool ServiceMgr::_TriggerQuit() 
{
    bool result = false;
    int quitFailCount = 0;

    for (unsigned i = 0; i < countof(m_services); ++i) 
	{
        if (m_services[i] && m_services[i]->IsRuning()) 
		{
            LogInfoFmtPrint("[server] notify service %s quit.", s_service_name[i].c_str());
            if (m_services[i]->Quit()) 
			{
                MMO_ASSERT(m_services[i]->IsQuitting());
            }
            else 
			{
                ++quitFailCount;
                LogErrFmtPrint("[server] service %s quit fail.", s_service_name[i].c_str());
            }
        }
    }

    MMOLOG_PROCESS_ERROR(quitFailCount == 0);

    result = true;;
Exit0:
    return result;
}

bool ServiceMgr::_HandleConsoleCmd() 
{
    bool result = false;

    if (m_consoleCmd.empty()) 
	{
        goto Exit1;
    }
    {
        std::queue<ConsoleCmd> commands;
        m_consoleCmdLock.Lock();
        m_consoleCmd.swap(commands);
        m_consoleCmdLock.Unlock();

        while (!commands.empty()) 
		{
            ConsoleCmd&  command = commands.front();
			LogDebugFmtPrint("[server] handle console command:%s", command.cmd);
            for (unsigned i = 0; i < countof(m_services); ++i) 
			{
                if (m_services[i]) 
				{
                    m_services[i]->HandleConsoleCmd(command.cmd);
                }
            }
            _ProcessCommand(command.cmd);
            commands.pop();
        }
    }
    
Exit1:
    result = true;
//Exit0:
    return result;
}

bool  ServiceMgr::_ProcessCommand(const char* cmd) 
{
    bool result  = false;
    bool retCode = false;

    if (stricmp(cmd, "q") == 0 || stricmp(cmd, "quit") == 0) 
	{
        SetExitSignal();
        goto Exit1;
    }

    if (stricmp(cmd, "start db") == 0) 
	{
        retCode = _AddService(DBPROXY_SERVER, "./config.lua");
        MMOLOG_PROCESS_ERROR(retCode);
    }

    if (stricmp(cmd, "start login") == 0) 
	{
        retCode = _AddService(LOGIN_SERVER, "./config.lua");
        MMOLOG_PROCESS_ERROR(retCode);
    }

    if (stricmp(cmd, "start log") == 0) 
	{
        retCode = _AddService(LOG_SERVER, "./config.lua");
        MMOLOG_PROCESS_ERROR(retCode);
    }

    if (stricmp(cmd, "start center") == 0) 
	{
        retCode = _AddService(CENTER_SERVER, "config.lua");
        MMOLOG_PROCESS_ERROR(retCode);
    }

    if (stricmp(cmd, "start logic") == 0) 
	{
        retCode = _AddService(LOGIC_SERVER, "config.lua");
        MMOLOG_PROCESS_ERROR(retCode);
    }

    if (stricmp(cmd, "shutdown logic") == 0) {
        if (m_services[LOGIC_SERVER]) {
			if (m_services[LOGIC_SERVER]->IsRuning()) 
			{
				retCode = m_services[LOGIC_SERVER]->Quit();
                MMOLOG_PROCESS_ERROR(retCode);
            }
        }
    }

    if (stricmp(cmd, "start all") == 0) 
	{
        retCode = _AddService(DBPROXY_SERVER, "config.lua");
        MMOLOG_PROCESS_ERROR(retCode);
        
        retCode = _AddService(LOGIN_SERVER, "config.lua");
        MMOLOG_PROCESS_ERROR(retCode);
        
        retCode = _AddService(LOG_SERVER, "config.lua");
        MMOLOG_PROCESS_ERROR(retCode);
        
        retCode = _AddService(CENTER_SERVER, "config.lua");
        MMOLOG_PROCESS_ERROR(retCode);
     
        retCode = _AddService(LOGIC_SERVER, "config.lua");
        MMOLOG_PROCESS_ERROR(retCode);
    }

    if (stricmp(cmd, "show") == 0)
	{
        OutputFmtToConsole("running service list");
        for (unsigned i = 0; i < countof(m_services); ++i) 
		{
            if (m_services[i]) 
			{
                OutputFmtToConsole("%s(%d)  is running",
									s_service_name[i].c_str(),
									m_services[i]->GetID());
            }
        }
        goto Exit1;
    }

    if (stricmp(cmd, "assert") == 0) 
	{
        MMO_ASSERT(false);
    }

    if (stricmp(cmd, "help") == 0 || stricmp(cmd, "h") == 0) 
	{
        OutputFmtToConsole("start dbp                  start dbproxy server");
        OutputFmtToConsole("start login                start login server");
        OutputFmtToConsole("start log                  start log server");
        OutputFmtToConsole("start center               start center server");
        OutputFmtToConsole("start logic                start logic server");
        OutputFmtToConsole("start all                  start all server");
        OutputFmtToConsole("show/sh                    list all start server");
        OutputFmtToConsole("quit/q                     stop all server then exit");
        goto Exit1;
    }

Exit1:
    result = true;
Exit0:
    return result;
}

bool ServiceMgr::_RegisteServiceMaker() 
{
    m_serviceMaker[DBPROXY_SERVER].Make = &MakeDBProxyService;
    m_serviceMaker[DBPROXY_SERVER].Del = &DeleteDBProxyService;
	m_serviceMaker[CENTER_SERVER].Make = &MakeCenterService;
	m_serviceMaker[CENTER_SERVER].Del = &DeleteCenterService;
	m_serviceMaker[LOGIC_SERVER].Make = &MakeLogicService;
	m_serviceMaker[LOGIC_SERVER].Del = &DeleteLogicService;
	m_serviceMaker[LOGIN_SERVER].Make = &MakeLoginService;
	m_serviceMaker[LOGIN_SERVER].Del = &DeleteLoginService;
	m_serviceMaker[LOG_SERVER].Make = &MakeLogService;
	m_serviceMaker[LOG_SERVER].Del = &DeleteLogService;
	m_serviceMaker[MASTER_SERVER].Make = &MakeMasterService;
	m_serviceMaker[MASTER_SERVER].Del  = &DeleteMasterService;
	m_serviceMaker[GATE_SERVER].Make = &MakeGateService;
	m_serviceMaker[GATE_SERVER].Del  = &DeleteGateService;
	m_serviceMaker[ZONE_SERVER].Make = &MakeZoneService;
	m_serviceMaker[ZONE_SERVER].Del  = &DeleteZoneService;


    return true;
}

bool ServiceMgr::_LoadConfig(const char* config, LogConfig& logConf)
{
	bool result = false;
	bool retCode = false;
	LuaParser  parser;
	std::string errLogPre;

	MMOLOG_ASSERT_EXIT(config);

	retCode = parser.OpenFile(config);
	MMOLOG_PROCESS_ERROR(retCode);

	retCode = parser.GetValue("NET_MAX_CONNETION", &m_netInit.max_conn);
	MMOLOG_PROCESS_ERROR(retCode);

	retCode = parser.GetValue("NET_TIMEOUT_MSEC", &m_netInit.timeout_ms);
	MMOLOG_PROCESS_ERROR(retCode);;

	retCode = parser.GetValue("LOG_INDEX", &logConf.logfileIndex);
	if (retCode== false)
		logConf.logfileIndex = s_logFileIdenty;

	retCode = parser.GetValue("LOG_MAXLINE", &logConf.maxLine);
	if (retCode == false)
		logConf.maxLine = s_maxLintCount;

	retCode = parser.GetValue("LOG_PRIORITY", &logConf.priority);
	if (retCode == false)
		logConf.priority = (uint16_t)LOG_PRIORITY_DEBUG;

	m_netInit.callback = &m_netCallback;
	result = true;
Exit0:
	return result;
}

bool ServiceMgr::_LogInit(LogConfig& logConf)
{
	bool result = false;
	bool retCode = false;

	retCode = InitLog(s_logDirector, logConf.logfileIndex.c_str(), logConf.maxLine);
	MMOLOG_PROCESS_ERROR(retCode);

	// log callback

	MMOLOG_PROCESS_ERROR(g_MakeErrCollectMgr());
	MMOLOG_PROCESS_ERROR(g_MakeProfileLogMgr());

	retCode = g_GetProfileLogMgr()->Init(logConf.logfileIndex);
	MMOLOG_PROCESS_ERROR(retCode);

	retCode = SetLogCallBack(ErrCollectMgr::CollectErr);
	MMOLOG_PROCESS_ERROR(retCode);

	retCode = SetLogPriorityLevel((LOG_PRIORITY)logConf.priority);
	MMOLOG_PROCESS_ERROR(retCode);

	retCode = EnableLogConsole(true);
	MMOLOG_PROCESS_ERROR(retCode);

	result = true;
Exit0:
	return result;
}

bool ServiceMgr::_LoadService(const char* config) 
{
    bool result = false;
    bool retCode = false;
    int count = 0;
    LuaParser  parser;
    ServiceType type = SERVER_TYPE_NULL;
	bool useTable = false;

    MMOLOG_ASSERT_EXIT(config);

    if (!parser.OpenFile(config)) 
	{
        goto Exit0;
    }
    {
        LuaRef table = parser.GetRef("StartService");
        if (!table.isTable()) 
		{
            LogErrFmtPrint("StartService config is error");
            _ProcessCommand("help");
        }

        count = table.length();
        MMOLOG_ASSERT_EXIT(count < (int)countof(m_services));
        for (int i = 0; i < count; ++i) 
		{
            LuaRef service = table[i + 1];
            type = (ServiceType)service["nType"].cast<int>();

			//ֻ�����ķ����߼�����Ҫ���ر��
			if (!useTable && (type == CENTER_SERVER || type == LOGIC_SERVER || type==ZONE_SERVER))
			{
					retCode = g_MakeTableDataMgr()->Init();
					MMOLOG_PROCESS_ERROR_INFO(retCode, "[server] table mgr init fail");
				
					retCode = g_MakeTableExMgr()->Init();
					MMOLOG_PROCESS_ERROR_INFO(retCode, "[server] tableex mgr init fail");
				
					retCode = g_MakeItemMgr()->Init();
					MMOLOG_PROCESS_ERROR_INFO(retCode, "[server] item mgr init fail");
				
					retCode = g_MakeAttrMgr()->Init();
					MMOLOG_PROCESS_ERROR_INFO(retCode, "[server] attr mgr init fail");

					retCode = g_MakeReliveMgr()->Init();
					MMOLOG_PROCESS_ERROR_INFO(retCode, "[server] relive mgr init fail");
				
				
				useTable = true;
			}

            retCode = _AddService(type, config);
            MMOLOG_PROCESS_ERROR(retCode);

			if (type == GATE_SERVER)
			{
				retCode = g_GetProfileLogMgr()->SetProfileOnlineCB(GateService::ProfileOnlineNum);
			}


        }
    }
    result = true;
Exit0:
    return result;
}

bool ServiceMgr::_AddService(ServiceType type, const char* configFile)
{
    bool result  = false;
    Service* service = NULL;

    MMOLOG_ASSERT_EXIT (m_serviceMaker[type].Make);
    MMOLOG_ASSERT_EXIT(m_serviceMaker[type].Del);

    if (m_services[type] != NULL)
	{
        LogInfoFmtPrint("%s service is running", s_service_name[type].c_str());
        goto Exit0;
    }

    LogInfoFmtPrint("start service %s...", s_service_name[type].c_str());

    service = m_serviceMaker[type].Make();
    MMOLOG_ASSERT_EXIT(service);
    MMO_ASSERT(service->GetType() == type);

    if (service->Init(m_net, configFile) == false)
	{
        m_serviceMaker[type].Del(service);
        LogErrFmtPrint("service %s start fail", s_service_name[type].c_str());
        goto Exit0;
    }

    m_services[type] = service;
    ++m_serviceCount;
    result = true;
Exit0:
    return result;
}

bool ServiceMgr::_DelService(Service* service) 
{
    bool result  = false;
    ServiceType type;

    MMOLOG_ASSERT_EXIT(service);
    type = service->GetType();

    LogInfoFmtPrint("stop service %s ...", s_service_name[type].c_str());

    MMOLOG_ASSERT_EXIT(m_serviceMaker[type].Del);
    service->UnInit();

    m_serviceMaker[type].Del(service);
    MMO_ASSERT(m_services[type]);
    m_services[type] = nullptr;

    MMO_ASSERT(m_serviceCount > 0);
    --m_serviceCount;
    
    result = true;
Exit0:
    return result;
}